﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Efcore.MultiTenant.DbProvider;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Efcore.MultiTenant.CacheKey;
using Efcore.MultiTenant.Entity;

namespace Efcore.MultiTenant
{
    public static class MultiTenantServiceExtension
    {
        /// <summary>
        ///  Efcore多租户
        /// </summary>
        /// <param name="services">ServiceCollection</param>
        /// <param name="optionAction">相关租户信息配置,DbOptionList未配置时，读取配置文件数据库连接ConnectionStrings</param>
        public static MultiTenantBuilder AddEfcoreMultiTenant<TDbContext>(this IServiceCollection services, Action<TenantOption> optionAction) where TDbContext:BaseDbContext
        {
            var option = new TenantOption<TDbContext>();
            optionAction?.Invoke(option);
            services.AddSingleton<TenantOption<TDbContext>>(provider => { 
                if (option.DbOptionList.Count == 0)
                {
                    option.AddDbConfig(provider);
                }
                return option;   });
            services.AddSingleton<IEntityScanner, EntityScanner>();
            services.AddScoped<TenantInfo>();
            services.AddScoped<IConnectionResolve<TDbContext>, ConnectionResolve<TDbContext>>();
            services.AddScoped<IDbProvider<TDbContext>, DbProvider<TDbContext>>();

            //efcore dbcontext register
            services.AddDbContext<TDbContext>((provider, optionBuilder) =>
            {
                //DbContextOptionBuilder配置
                var dbProvider = provider.GetRequiredService<IDbProvider<TDbContext>>();
                dbProvider.OnConfiguring(optionBuilder);
                option.DbContextBuildAction?.Invoke(optionBuilder);
            });

            return new MultiTenantBuilder(services);
        }

        /// <summary>
        ///  Efcore多租户,使用默认BaseDbContext
        /// </summary>
        /// <param name="services">ServiceCollection</param>
        /// <param name="optionAction">相关租户信息配置,DbOptionList未配置时，读取配置文件数据库连接ConnectionStrings</param>
        public static MultiTenantBuilder AddEfcoreMultiTenant(this IServiceCollection services, Action<TenantOption> optionAction)
        {
            return services.AddEfcoreMultiTenant<BaseDbContext>(optionAction);
        }

        #region private methods

        private static void AddDbConfig(this TenantOption tenantOption, IServiceProvider serviceProvider)
        {
            var configuration = serviceProvider.GetRequiredService<IConfiguration>();
            var connDic = configuration.GetSection("ConnectionStrings").Get<Dictionary<string, string>>();
            if (connDic == default(Dictionary<string, string>) || connDic.Count == 0)
            {
                throw new Exception("configure at least one item for the database");
            }
            foreach (var item in connDic)
            {
                tenantOption.DbOptionList.Add(new DbOption { DbKey = item.Key, DbConnectionString = item.Value });
            }
        }

        #endregion
    }
}
